package logger

import (
	"context"
	"errors"
	"fmt"
	"time"

	"gorm.io/gorm"
	"gorm.io/gorm/logger"

	"gitee.com/csingo/cLog"
)

type GormLogger struct {
	logger.Config
}

func NewGormLogger(writer logger.Writer, config logger.Config) logger.Interface {
	return &GormLogger{
		Config: config,
	}
}

func (i *GormLogger) LogMode(level logger.LogLevel) logger.Interface {
	newLogger := *i
	newLogger.LogLevel = level
	return &newLogger
}

func (i *GormLogger) Info(ctx context.Context, msg string, data ...interface{}) {
	if i.LogLevel >= logger.Info {
		cLog.WithContext(ctx, map[string]any{
			"msg": fmt.Sprintf(msg, data...),
		}).Info("SQL 执行完成")
	}
}

func (i *GormLogger) Warn(ctx context.Context, msg string, data ...interface{}) {
	if i.LogLevel >= logger.Warn {
		cLog.WithContext(ctx, map[string]any{
			"msg": fmt.Sprintf(msg, data...),
		}).Warn("SQL 告警")
	}
}

func (i *GormLogger) Error(ctx context.Context, msg string, data ...interface{}) {
	if i.LogLevel >= logger.Error {
		cLog.WithContext(ctx, map[string]any{
			"msg": fmt.Sprintf(msg, data...),
		}).Error("SQL 执行错误")
	}
}

func (i *GormLogger) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
	if i.LogLevel <= logger.Silent {
		return
	}

	elapsed := time.Since(begin)
	sql, rows := fc()
	switch {
	case err != nil && i.LogLevel >= logger.Error && (!errors.Is(err, gorm.ErrRecordNotFound) || !i.IgnoreRecordNotFoundError):
		cLog.WithContext(ctx, map[string]any{
			"err":  err.Error(),
			"sql":  sql,
			"rows": rows,
			"cost": fmt.Sprintf("%.2f ms", float64(elapsed.Nanoseconds()/1e6)),
		}).Error("SQL 执行错误")
	case elapsed > i.SlowThreshold && i.SlowThreshold != 0 && i.LogLevel >= logger.Warn:
		cLog.WithContext(ctx, map[string]any{
			"sql":  sql,
			"rows": rows,
			"cost": fmt.Sprintf("%.2f ms", float64(elapsed.Nanoseconds()/1e6)),
		}).Warn("SQL 慢查询")
	case i.LogLevel == logger.Info:
		cLog.WithContext(ctx, map[string]any{
			"sql":  sql,
			"rows": rows,
			"cost": fmt.Sprintf("%.2f ms", float64(elapsed.Nanoseconds()/1e6)),
		}).Trace("SQL 执行完成")
	}
}
